/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package org.jackysoft.opensymphony.workflow;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jackysoft.entity.AbstractWorkflowEntry;
import org.jackysoft.entity.HibernateStep;
import org.jackysoft.entity.HibernateWorkflowEntry;
import org.jackysoft.entity.Step;
import org.jackysoft.entity.Variable;
import org.jackysoft.entity.WorkflowEntry;
import org.jackysoft.opensymphony.workflow.config.Configuration;
import org.jackysoft.opensymphony.workflow.entity.AbstractDescriptor;
import org.jackysoft.opensymphony.workflow.entity.ActionDescriptor;
import org.jackysoft.opensymphony.workflow.entity.ConditionDescriptor;
import org.jackysoft.opensymphony.workflow.entity.ConditionalResultDescriptor;
import org.jackysoft.opensymphony.workflow.entity.ConditionsDescriptor;
import org.jackysoft.opensymphony.workflow.entity.FunctionDescriptor;
import org.jackysoft.opensymphony.workflow.entity.JoinDescriptor;
import org.jackysoft.opensymphony.workflow.entity.PermissionDescriptor;
import org.jackysoft.opensymphony.workflow.entity.RegisterDescriptor;
import org.jackysoft.opensymphony.workflow.entity.RestrictionDescriptor;
import org.jackysoft.opensymphony.workflow.entity.ResultDescriptor;
import org.jackysoft.opensymphony.workflow.entity.SplitDescriptor;
import org.jackysoft.opensymphony.workflow.entity.StepDescriptor;
import org.jackysoft.opensymphony.workflow.entity.ValidatorDescriptor;
import org.jackysoft.opensymphony.workflow.entity.WorkflowDescriptor;
import org.jackysoft.opensymphony.workflow.util.OwnerResolver;
import org.jackysoft.opensymphony.workflow.util.VariableResolver;
import org.jackysoft.opensymphony.workflow.util.WorkflowResultType;
import org.jackysoft.service.VariableService;
import org.jackysoft.service.VariableSettingService;
import org.jackysoft.service.WorkflowService;
import org.jackysoft.util.SpringSecurityUtils;
import org.jackysoft.util.WorkflowConstant;
import org.jackysoft.workflow.ActionItem;
import org.jackysoft.workflow.StepOwner;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
 * Abstract workflow instance that serves as the base for specific
 * implementations, such as EJB or SOAP.
 * 
 * @author <a href="mailto:plightbo@hotmail.com">Pat Lightbody</a>
 * @author Hani Suleiman
 */
public class AbstractWorkflow implements Workflow,ApplicationContextAware {
	// ~ Static fields/initializers
	// /////////////////////////////////////////////

	

	protected static final Log log = LogFactory.getLog(AbstractWorkflow.class);

	// ~ Instance fields
	// ////////////////////////////////////////////////////////
	protected ApplicationContext springContext;
	protected WorkflowContext context;
	private Configuration configuration;
	@SuppressWarnings("rawtypes")
	private ThreadLocal stateCache = new ThreadLocal();
	private TypeResolver typeResolver;
	private VariableSettingService variableSettingService;

	// ~ Constructors
	// ///////////////////////////////////////////////////////////

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public AbstractWorkflow() {
		stateCache.set(new HashMap());
	}

	@Resource(name = "workflowConfiguration")
	public void setConfiguration(Configuration configuration) {
		this.configuration = configuration;
	}

	// ~ Methods
	// ////////////////////////////////////////////////////////////////

	/**
	 * 获得指定工作流实例的可用action
	 * 
	 * @param id
	 *            工作流ID
	 * @param inputs
	 *            传入条件的参数
	 * @return 可用的action数组
	 * @throws IllegalArgumentException
	 *             <dd>如果指定的工作流不存在,或者其描述文件不可用
	 */
	public int[] getAvailableActions(long id, Map inputs)
			throws IllegalArgumentException {
		try {
			WorkflowService store = getPersistence();
			WorkflowEntry entry = store.findEntry(id);

			if (entry == null) {
				throw new IllegalArgumentException("No such workflow id " + id);
			}

			if (entry.getState() != WorkflowEntry.ACTIVATED) {
				return new int[0];
			}

			WorkflowDescriptor wf = getWorkflowDescriptor(entry
					.getWorkflowName());

			if (wf == null) {
				throw new IllegalArgumentException("No such workflow "
						+ entry.getWorkflowName());
			}

			List lactions = new ArrayList();
			Map transientVars = (inputs == null) ? new HashMap() : new HashMap(
					inputs);
			Collection currentSteps = store.findCurrentSteps(id);

			populateTransientMap(entry, transientVars, wf.getRegisters(),
					new Integer(0), currentSteps);

			// get global actions
			List globalActions = wf.getGlobalActions();

			for (Iterator iterator = globalActions.iterator(); iterator
					.hasNext();) {
				ActionDescriptor action = (ActionDescriptor) iterator.next();

				RestrictionDescriptor restriction = action.getRestriction();
				ConditionsDescriptor conditions = null;

				transientVars.put("actionId", new Integer(action.getId()));

				if (restriction != null) {
					conditions = restriction.getConditionsDescriptor();
				}

				// todo verify that 0 is the right currentStepId
				if (passesConditions(wf.getGlobalConditions(), transientVars, 0)
						&& passesConditions(conditions, transientVars, 0)) {
					lactions.add(new Integer(action.getId()));
				}
			}

			// get normal actions
			for (Iterator iterator = currentSteps.iterator(); iterator
					.hasNext();) {
				Step step = (Step) iterator.next();
				lactions.addAll(getAvailableActionsForStep(wf, step,
						transientVars));
			}

			int[] actions = new int[lactions.size()];

			for (int i = 0; i < actions.length; i++) {
				actions[i] = ((Integer) lactions.get(i)).intValue();
			}

			return actions;
		} catch (Exception e) {
			log.error("Error checking available actions", e);

			return new int[0];
		}
	}

	/**
	 * Get the configuration for this workflow. This method also checks if the
	 * configuration has been initialized, and if not, initializes it.
	 * 
	 * @return The configuration that was set. If no configuration was set, then
	 *         the default (static) configuration is returned.
	 * 
	 */
	public Configuration getConfiguration() {

		return configuration;
	}

	/**
	 * @param Long
	 *            id 工作流实体编号
	 * @return List 当前步骤的编号集合
	 */
	public List getCurrentSteps(long id) {
		WorkflowService store = getPersistence();

		return store.findCurrentSteps(id);
	}

	/**
	 * @ejb.interface-method
	 */
	public int getEntryState(long id) {
		WorkflowService store = getPersistence();
		return store.findEntry(id).getState();

	}

	/**
	 * @ejb.interface-method
	 */
	public List getHistorySteps(long id) {
		WorkflowService store = getPersistence();
		return store.findHistorySteps(id);

	}

	/**
	 * @ejb.interface-method
	 */
	public Properties getPersistenceProperties() {
		Properties p = new Properties();
		Iterator iter = getConfiguration().getPersistenceArgs().entrySet()
				.iterator();

		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			p.setProperty((String) entry.getKey(), (String) entry.getValue());
		}

		return p;
	}

	@Resource
	public void setResolver(TypeResolver resolver) {
		this.typeResolver = resolver;
	}

	public TypeResolver getResolver() {
		if (typeResolver == null) {
			typeResolver = TypeResolver.getResolver();
		}

		return typeResolver;
	}

	/**
	 * @ejb.interface-method
	 */
	public List getSecurityPermissions(long id, Map inputs) {
		try {
			WorkflowService store = getPersistence();
			
			WorkflowEntry entry = store.findEntry(id);
			WorkflowDescriptor wf = getWorkflowDescriptor(entry
					.getWorkflowName());

			Map transientVars = (inputs == null) ? new HashMap() : new HashMap(
					inputs);
			Collection currentSteps = store.findCurrentSteps(id);
			populateTransientMap(entry, transientVars, wf.getRegisters(), null,
					currentSteps);

			List s = new ArrayList();

			for (Iterator interator = currentSteps.iterator(); interator
					.hasNext();) {
				Step step = (Step) interator.next();

				int stepId = step.getStepId();

				StepDescriptor xmlStep = wf.getStep(stepId);

				List securities = xmlStep.getPermissions();

				for (Iterator iterator2 = securities.iterator(); iterator2
						.hasNext();) {
					PermissionDescriptor security = (PermissionDescriptor) iterator2
							.next();

					// to have the permission, the condition must be met or not
					// specified
					// securities can't have restrictions based on inputs, so
					// it's null
					if (security.getRestriction() != null) {
						if (passesConditions(security.getRestriction()
								.getConditionsDescriptor(), transientVars,
								xmlStep.getId())) {
							s.add(security.getName());
						}
					}
				}
			}

			return s;
		} catch (Exception e) {
			log.error("Error getting security permissions for instance #" + id,
					e);
		}

		return Collections.EMPTY_LIST;
	}

	/**
	 * Returns a workflow definition object associated with the given name.
	 * 
	 * @param workflowName
	 *            the name of the workflow
	 * @return the object graph that represents a workflow definition
	 * @ejb.interface-method
	 */
	public WorkflowDescriptor getWorkflowDescriptor(String workflowName) {
		try {
			return getConfiguration().getWorkflowService()
					.getWorkflowDescriptor(workflowName);

		} catch (StoreException e) {
			e.printStackTrace();
		}

		return null;
	}

	/**
	 * @ejb.interface-method
	 */
	public String getWorkflowName(long id) {
		WorkflowService store = getPersistence();
		WorkflowEntry entry = store.findEntry(id);

		if (entry != null) {
			return entry.getWorkflowName();
		}

		return null;
	}

	/**
	 * @ejb.interface-method
	 */
	public boolean canInitialize(String workflowName, int initialAction) {
		return canInitialize(workflowName, initialAction, null);
	}

	/**
	 * @ejb.interface-method
	 * @param workflowName
	 *            the name of the workflow to check
	 * @param initialAction
	 *            The initial action to check
	 * @param inputs
	 *            the inputs map
	 * @return true if the workflow can be initialized
	 */
	public boolean canInitialize(String workflowName, int initialAction,
			Map inputs) {
		WorkflowEntry mockEntry = new AbstractWorkflowEntry(workflowName);

		// since no state change happens here, a memory instance is just fine
		Map transientVars = new HashMap();

		if (inputs != null) {
			transientVars.putAll(inputs);
		}

		try {
			populateTransientMap(mockEntry, transientVars,
					Collections.EMPTY_LIST, new Integer(initialAction),
					Collections.EMPTY_LIST);

			return canInitializeWorkflow(workflowName, initialAction,
					transientVars);
		} catch (InvalidActionException e) {
			log.error(e.getMessage());

			return false;
		} catch (WorkflowException e) {
			log.error("Error checking canInitialize", e);

			return false;
		}
	}

	/**
	 * @ejb.interface-method
	 */
	public boolean canModifyEntryState(long id, int newState) {
		WorkflowService store = getPersistence();
		WorkflowEntry entry = store.findEntry(id);
		int currentState = entry.getState();
		boolean result = false;

		switch (newState) {
		case WorkflowEntry.COMPLETED:

			if (currentState == WorkflowEntry.ACTIVATED) {
				result = true;
			}

			break;

		case WorkflowEntry.CREATED:
			result = false;

		case WorkflowEntry.ACTIVATED:

			if ((currentState == WorkflowEntry.CREATED)
					|| (currentState == WorkflowEntry.SUSPENDED)) {
				result = true;
			}

			break;

		case WorkflowEntry.SUSPENDED:

			if (currentState == WorkflowEntry.ACTIVATED) {
				result = true;
			}

			break;

		case WorkflowEntry.KILLED:

			if ((currentState == WorkflowEntry.CREATED)
					|| (currentState == WorkflowEntry.ACTIVATED)
					|| (currentState == WorkflowEntry.SUSPENDED)) {
				result = true;
			}

			break;

		default:
			result = false;

			break;
		}

		return result;
	}

	public void changeEntryState(long id, int newState)
			throws WorkflowException {
		WorkflowService store = getPersistence();
		WorkflowEntry entry = store.findEntry(id);

		if (entry.getState() == newState) {
			return;
		}
		log.info("Current state can " + canModifyEntryState(id, newState));

		if (canModifyEntryState(id, newState)) {
			if ((newState == WorkflowEntry.KILLED)
					|| (newState == WorkflowEntry.COMPLETED)) {
				Collection currentSteps = getCurrentSteps(id);

				if (currentSteps.size() > 0) {
					completeEntry(null, id, currentSteps, newState);
				}
			}

			log.info("State is " + id + "," + newState);
			store.setEntryState(id, newState);
		} else {
			throw new InvalidEntryStateException(
					"Can't transition workflow instance #" + id
							+ ". Current state is " + entry.getState()
							+ ", requested state is " + newState);
		}

		if (log.isDebugEnabled()) {
			log.debug(entry.getId() + " : State is now : " + entry.getState());
		}
	}

	public void doAction(long id, int actionId, Map inputs,
			Collection<StepOwner> owners) throws WorkflowException {
		WorkflowService store = getPersistence();
		WorkflowEntry entry = store.findEntry(id);

		if (entry.getState() != WorkflowEntry.ACTIVATED) {
			return;
		}

		WorkflowDescriptor wf = getConfiguration().getWorkflowService()
				.getWorkflowDescriptor(entry.getWorkflowName());

		List currentSteps = store.findCurrentSteps(id);
		ActionDescriptor action = null;

		Map transientVars = new HashMap();

		if (inputs != null) {
			transientVars.putAll(inputs);
		}

		populateTransientMap(entry, transientVars, wf.getRegisters(),
				new Integer(actionId), currentSteps);

		boolean validAction = false;

		// check global actions
		for (Iterator gIter = wf.getGlobalActions().iterator(); !validAction
				&& gIter.hasNext();) {
			ActionDescriptor actionDesc = (ActionDescriptor) gIter.next();

			if (actionDesc.getId() == actionId) {
				action = actionDesc;

				if (isActionAvailable(action, transientVars, 0)) {
					validAction = true;
				}
			}
		}

		for (Iterator iter = currentSteps.iterator(); !validAction
				&& iter.hasNext();) {
			Step step = (Step) iter.next();
			StepDescriptor s = wf.getStep(step.getStepId());

			for (Iterator iterator = s.getActions().iterator(); !validAction
					&& iterator.hasNext();) {
				ActionDescriptor actionDesc = (ActionDescriptor) iterator
						.next();

				if (actionDesc.getId() == actionId) {
					action = actionDesc;

					if (isActionAvailable(action, transientVars, s.getId())) {
						validAction = true;
					}
				}
			}
		}

		if (!validAction) {

		}

		try {
			// this.getNextSteps(id, actionId);

			// NEXTOWNERAVALIABLE
			// transition the workflow, if it wasn't explicitly finished, check
			// for an implicit finish
			/**
			 * currentSteps 的来源来自这个实体的当前步骤
			 * */
			boolean istransition = transitionWorkflow(entry, currentSteps,
					store, wf, action, transientVars, inputs, owners);
			if (!istransition) {
				checkImplicitFinish(action, id);
			}

		} catch (WorkflowException e) {
			context.setRollbackOnly();
			throw e;
		}
	}

	public void executeTriggerFunction(long id, int triggerId)
			throws WorkflowException {
		WorkflowService store = getPersistence();
		WorkflowEntry entry = store.findEntry(id);

		if (entry == null) {
			log.warn("Cannot execute trigger #" + triggerId
					+ " on non-existent workflow id#" + id);

			return;
		}

		WorkflowDescriptor wf = getConfiguration().getWorkflowService()
				.getWorkflowDescriptor(entry.getWorkflowName());

		Map transientVars = new HashMap();
		populateTransientMap(entry, transientVars, wf.getRegisters(), null,
				store.findCurrentSteps(id));
		executeFunction(wf.getTriggerFunction(triggerId), transientVars);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public long initialize(String workflowName, int initialAction, Map inputs)
			throws InvalidRoleException, InvalidInputException,
			WorkflowException {
		WorkflowService store = getPersistence();
		WorkflowDescriptor wf = store.getWorkflowDescriptor(workflowName);
		ActionDescriptor initAct = wf.getInitialAction(initialAction);
		int startStep = initAct.getUnconditionalResult().getStep();
		// Entry state is CREATED
		WorkflowEntry entry = store.createEntry(workflowName);

		// start with a memory property set, but clone it after we have an ID
		Map<String, Object> transientVars = new HashMap<String, Object>();
		String user = SpringSecurityUtils.getCurrentUserName();
		StepOwner so = new StepOwner();
		so.setOwner(user);
		so.setStepId(startStep + "");
		Collection<StepOwner> cs = new ArrayList<StepOwner>();
		cs.add(so);
		transientVars.put(WorkflowConstant.NEXTOWNER.toString(), cs);
		if (inputs != null) {
			transientVars.putAll(inputs);
		}

		List regs = wf.getRegisters();

		populateTransientMap(entry, transientVars, regs, initialAction,
				Collections.emptyList());

		if (!canInitialize(workflowName, initialAction, transientVars)) {
			context.setRollbackOnly();
			throw new InvalidRoleException(
					"You are restricted from initializing this workflow");
		}

		try {
			/**
			 * 由于是第一次初始化,所以,currentsteps集合当然为空
			 * */
			transitionWorkflow(entry, Collections.emptyList(), store, wf,
					initAct, transientVars, inputs, cs);

		} catch (WorkflowException e) {
			context.setRollbackOnly();
			throw e;
		}

		long entryId = entry.getId();

		return entryId;
	}

	protected List getAvailableActionsForStep(WorkflowDescriptor wf, Step step,
			Map transientVars) throws WorkflowException {
		List laction = new ArrayList();
		StepDescriptor s = wf.getStep(step.getStepId());

		if (s == null) {
			log.warn("getAvailableActionsForStep called for non-existent step Id #"
					+ step.getStepId());

			return laction;
		}

		List actions = s.getActions();

		if ((actions == null) || (actions.size() == 0)) {
			return laction;
		}

		for (Iterator iterator2 = actions.iterator(); iterator2.hasNext();) {
			ActionDescriptor action = (ActionDescriptor) iterator2.next();
			RestrictionDescriptor restriction = action.getRestriction();
			ConditionsDescriptor conditions = null;

			transientVars.put("actionId", new Integer(action.getId()));

			if (restriction != null) {
				conditions = restriction.getConditionsDescriptor();
			}

			if (passesConditions(wf.getGlobalConditions(), new HashMap(
					transientVars), s.getId())
					&& passesConditions(conditions, new HashMap(transientVars),
							s.getId())) {
				laction.add(new Integer(action.getId()));
			}
		}

		return laction;
	}

	protected int[] getAvailableAutoActions(long id, Map inputs) {
		try {
			WorkflowService store = getPersistence();
			WorkflowEntry entry = store.findEntry(id);

			if (entry == null) {
				throw new IllegalArgumentException("No such workflow id " + id);
			}

			if (entry.getState() != WorkflowEntry.ACTIVATED) {
				log.debug("--> state is " + entry.getState());

				return new int[0];
			}

			WorkflowDescriptor wf = getConfiguration().getWorkflowService()
					.getWorkflowDescriptor(entry.getWorkflowName());

			if (wf == null) {
				throw new IllegalArgumentException("No such workflow "
						+ entry.getWorkflowName());
			}

			List l = new ArrayList();
			Map transientVars = (inputs == null) ? new HashMap() : new HashMap(
					inputs);
			Collection currentSteps = store.findCurrentSteps(id);

			populateTransientMap(entry, transientVars, wf.getRegisters(),
					new Integer(0), currentSteps);

			// get global actions
			List globalActions = wf.getGlobalActions();

			for (Iterator iterator = globalActions.iterator(); iterator
					.hasNext();) {
				ActionDescriptor action = (ActionDescriptor) iterator.next();

				transientVars.put("actionId", new Integer(action.getId()));

				if (action.getAutoExecute()) {
					if (isActionAvailable(action, transientVars, 0)) {
						l.add(new Integer(action.getId()));
					}
				}
			}

			// get normal actions
			for (Iterator iterator = currentSteps.iterator(); iterator
					.hasNext();) {
				Step step = (Step) iterator.next();
				l.addAll(getAvailableAutoActionsForStep(wf, step, transientVars));
			}

			int[] actions = new int[l.size()];

			for (int i = 0; i < actions.length; i++) {
				actions[i] = ((Integer) l.get(i)).intValue();
			}

			return actions;
		} catch (Exception e) {
			log.error("Error checking available actions", e);

			return new int[0];
		}
	}

	/**
	 * Get just auto action availables for a step
	 */
	protected List getAvailableAutoActionsForStep(WorkflowDescriptor wf,
			Step step, Map transientVars) throws WorkflowException {
		List l = new ArrayList();
		StepDescriptor s = wf.getStep(step.getStepId());

		if (s == null) {
			log.warn("getAvailableAutoActionsForStep called for non-existent step Id #"
					+ step.getStepId());

			return l;
		}

		List actions = s.getActions();

		if ((actions == null) || (actions.size() == 0)) {
			return l;
		}

		for (Iterator iterator2 = actions.iterator(); iterator2.hasNext();) {
			ActionDescriptor action = (ActionDescriptor) iterator2.next();

			transientVars.put("actionId", new Integer(action.getId()));

			// check auto
			if (action.getAutoExecute()) {
				if (isActionAvailable(action, transientVars, s.getId())) {
					l.add(new Integer(action.getId()));
				}
			}
		}

		return l;
	}

	protected WorkflowService getPersistence() {
		WorkflowService ws = null;
		try {
			ws = getConfiguration().getWorkflowService();
		} catch (StoreException e) {
			throw new RuntimeException(e);

		}
		return ws;
	}

	protected void checkImplicitFinish(ActionDescriptor action, long id)
			throws WorkflowException {
		WorkflowService store = getPersistence();
		WorkflowEntry entry = store.findEntry(id);

		WorkflowDescriptor wf = getConfiguration().getWorkflowService()
				.getWorkflowDescriptor(entry.getWorkflowName());

		Collection currentSteps = store.findCurrentSteps(id);

		boolean isCompleted = true;

		for (Iterator iterator = currentSteps.iterator(); iterator.hasNext();) {
			Step step = (Step) iterator.next();
			StepDescriptor stepDes = wf.getStep(step.getStepId());

			// if at least on current step have an available action
			if (stepDes.getActions().size() > 0) {
				isCompleted = false;
			}
		}

		if (isCompleted) {
			completeEntry(action, id, currentSteps, WorkflowEntry.COMPLETED);
		}
	}

	/**
	 * Mark the specified entry as completed, and move all current steps to
	 * history.
	 */
	protected void completeEntry(ActionDescriptor action, long id,
			Collection currentSteps, int state) throws StoreException {
		getPersistence().setEntryState(id, state);

		Iterator i = new ArrayList(currentSteps).iterator();

		while (i.hasNext()) {
			Step step = (Step) i.next();
			String oldStatus = (action != null) ? action
					.getUnconditionalResult().getOldStatus() : "Finished";
			getPersistence().markFinished(step,
					(action != null) ? action.getId() : (-1), new Date(),
					oldStatus, context.getCaller());
			getPersistence().moveToHistory(step);
		}
	}

	/**
	 * 执行用户所提供的function类的execute方法来执行function的功能
	 * 
	 * @param function
	 *            the function to execute
	 * @param transientVars
	 *            the transientVars given by the end-user
	 * @param ps
	 *            the persistence variables
	 */
	protected void executeFunction(FunctionDescriptor function,
			Map transientVars) throws WorkflowException {
		if (function != null) {
			String type = function.getType();

			Map args = new HashMap(function.getArgs());

			for (Iterator iterator = args.entrySet().iterator(); iterator
					.hasNext();) {
				Map.Entry mapEntry = (Map.Entry) iterator.next();
				mapEntry.setValue(getConfiguration()
						.getVariableResolver()
						.translateVariables(
								(String) mapEntry.getValue(),
								transientVars,
								this.configuration.getWorkflowVariableService(),
								variableSettingService));
			}

			FunctionProvider provider = getResolver().getFunction(type, args);

			if (provider == null) {
				String message = "Could not load FunctionProvider class";
				context.setRollbackOnly();
				throw new WorkflowException(message);
			}

			try {
				provider.execute(transientVars, args, this.getConfiguration()
						.getWorkflowVariableService());
			} catch (WorkflowException e) {
				context.setRollbackOnly();
				throw e;
			}
		}
	}

	protected boolean passesCondition(ConditionDescriptor conditionDesc,
			Map transientVars, int currentStepId) throws WorkflowException {
		String type = conditionDesc.getType();

		Map args = new HashMap(conditionDesc.getArgs());

		for (Iterator iterator = args.entrySet().iterator(); iterator.hasNext();) {
			Map.Entry mapEntry = (Map.Entry) iterator.next();
			mapEntry.setValue(getConfiguration().getVariableResolver()
					.translateVariables((String) mapEntry.getValue(),
							transientVars,
							this.configuration.getWorkflowVariableService(),
							variableSettingService));
		}

		if (currentStepId != -1) {
			Object stepId = args.get("stepId");

			if ((stepId != null) && stepId.equals("-1")) {
				args.put("stepId", String.valueOf(currentStepId));
			}
		}

		Condition condition = getResolver().getCondition(type, args);

		if (condition == null) {
			context.setRollbackOnly();
			throw new WorkflowException("Could not load condition");
		}

		try {
			boolean passed = condition.passesCondition(transientVars, args,
					this.configuration.getWorkflowVariableService());

			if (conditionDesc.isNegate()) {
				passed = !passed;
			}

			return passed;
		} catch (Exception e) {
			context.setRollbackOnly();

			if (e instanceof WorkflowException) {
				throw (WorkflowException) e;
			}

			throw new WorkflowException(
					"Unknown exception encountered when checking condition "
							+ condition, e);
		}
	}

	protected boolean passesConditions(String conditionType, List conditions,
			Map transientVars, int currentStepId) throws WorkflowException {
		if ((conditions == null) || (conditions.size() == 0)) {
			return true;
		}

		boolean and = "AND".equals(conditionType);
		boolean or = !and;

		for (Iterator iterator = conditions.iterator(); iterator.hasNext();) {
			AbstractDescriptor descriptor = (AbstractDescriptor) iterator
					.next();
			boolean result;

			if (descriptor instanceof ConditionsDescriptor) {
				ConditionsDescriptor conditionsDescriptor = (ConditionsDescriptor) descriptor;
				result = passesConditions(conditionsDescriptor.getType(),
						conditionsDescriptor.getConditions(), transientVars,
						currentStepId);
			} else {
				result = passesCondition((ConditionDescriptor) descriptor,
						transientVars, currentStepId);
			}

			if (and && !result) {
				return false;
			} else if (or && result) {
				return true;
			}
		}

		if (and) {
			return true;
		} else if (or) {
			return false;
		} else {
			return false;
		}
	}

	protected boolean passesConditions(ConditionsDescriptor descriptor,
			Map transientVars, int currentStepId) throws WorkflowException {
		if (descriptor == null) {
			return true;
		}

		return passesConditions(descriptor.getType(),
				descriptor.getConditions(), transientVars, currentStepId);
	}

	protected void populateTransientMap(WorkflowEntry entry, Map transientVars,
			List registers, Integer actionId, Collection currentSteps)
			throws WorkflowException {

		transientVars.put("context", context);
		transientVars.put("entry", entry);
		transientVars.put("store", getPersistence());
		transientVars.put("configuration", getConfiguration());
		transientVars.put("descriptor", getConfiguration().getWorkflowService()
				.getWorkflowDescriptor(entry.getWorkflowName()));

		if (actionId != null) {
			transientVars.put("actionId", actionId);
		}

		transientVars.put("currentSteps", new ArrayList(currentSteps));

		// now talk to the registers for any extra objects needed in scope
		for (Iterator iterator = registers.iterator(); iterator.hasNext();) {
			RegisterDescriptor register = (RegisterDescriptor) iterator.next();
			Map args = register.getArgs();

			String type = register.getType();

			Register r = getResolver().getRegister(type, args);

			if (r == null) {
				String message = "Could not load register class";
				context.setRollbackOnly();
				throw new WorkflowException(message);
			}

			try {
				transientVars
						.put(register.getVariableName(),
								r.registerVariable(context, entry, args,
										this.configuration
												.getWorkflowVariableService()));
			} catch (Exception e) {
				context.setRollbackOnly();

				if (e instanceof WorkflowException) {
					throw (WorkflowException) e;
				}

				throw new WorkflowException(
						"An unknown exception occured while registering variable using register "
								+ r, e);
			}
		}
	}

	/**
	 * 
	 * @return true if the instance has been explicitly completed is this
	 *         transition, false otherwise
	 * @throws WorkflowException
	 **/
	protected boolean transitionWorkflow(WorkflowEntry entry,
			List currentSteps, WorkflowService store, WorkflowDescriptor wf,
			ActionDescriptor action, Map transientVars, Map inputs,
			Collection<StepOwner> owners) throws WorkflowException {
		Map cache = (Map) stateCache.get();

		if (cache != null) {
			cache.clear();
		} else {
			stateCache.set(new HashMap());
		}

		// 解析owner

		if (CollectionUtils.isEmpty(owners))
			throw new UsernameNotFoundException("没有设置流程接收用户!");

		OwnerResolver orl = new OwnerResolver(owners,
				this.configuration.getVariableResolver(), transientVars,
				this.configuration.getWorkflowVariableService(),
				variableSettingService);
		// orl.setOwner(rd, wt);
		Step step = getCurrentStep(wf, action.getId(), currentSteps,
				transientVars);

		if (action.getValidators().size() > 0) {
			verifyInputs(entry, action.getValidators(),
					Collections.unmodifiableMap(transientVars));
		}

		// we're leaving the current step, so let's execute its post-functions
		// check if we actually have a current step
		if (step != null) {
			List stepPostFunctions = wf.getStep(step.getStepId())
					.getPostFunctions();
			for (Iterator iterator = stepPostFunctions.iterator(); iterator
					.hasNext();) {
				FunctionDescriptor function = (FunctionDescriptor) iterator
						.next();
				executeFunction(function, transientVars);
			}
		}

		// preFunctions
		// 执行action的预处理功能
		List preFunctions = action.getPreFunctions();

		for (Iterator iterator = preFunctions.iterator(); iterator.hasNext();) {
			FunctionDescriptor function = (FunctionDescriptor) iterator.next();
			executeFunction(function, transientVars);
		}

		// check each conditional result
		// 检查这个action的条件结果类型
		List conditionalResults = action.getConditionalResults();
		List extraPreFunctions = null;
		List extraPostFunctions = null;
		ResultDescriptor[] theResults = new ResultDescriptor[1];

		// 遍历执行条件函数
		for (Iterator iterator = conditionalResults.iterator(); iterator
				.hasNext();) {
			ConditionalResultDescriptor conditionalResult = (ConditionalResultDescriptor) iterator
					.next();

			if (passesConditions(null, conditionalResult.getConditions(),
					Collections.unmodifiableMap(transientVars),
					(step != null) ? step.getStepId() : (-1))) {
				// if (evaluateExpression(conditionalResult.getCondition(),
				// entry, wf.getRegisters(), null, transientVars)) {
				theResults[0] = conditionalResult;
				log.info("转向用户:" + theResults[0].getOwner());
				if (conditionalResult.getValidators().size() > 0) {
					verifyInputs(entry, conditionalResult.getValidators(),
							Collections.unmodifiableMap(transientVars));
				}

				extraPreFunctions = conditionalResult.getPreFunctions();
				extraPostFunctions = conditionalResult.getPostFunctions();

				break;
			}
		}

		// use unconditional-result if a condition hasn't been met
		// 如果条件结果类型的条件没通过,或者没有定义条件结果类型就使用无条件结果类型
		if (theResults[0] == null) {
			theResults[0] = action.getUnconditionalResult();
			log.info("转向用户:" + theResults[0].getOwner());
			verifyInputs(entry, theResults[0].getValidators(),
					Collections.unmodifiableMap(transientVars));
			extraPreFunctions = theResults[0].getPreFunctions();
			extraPostFunctions = theResults[0].getPostFunctions();
		}

		if (log.isDebugEnabled()) {
			log.debug("theResult=" + theResults[0].getStep() + ' '
					+ theResults[0].getStatus());
		}

		if ((extraPreFunctions != null) && (extraPreFunctions.size() > 0)) {
			// run any extra pre-functions that haven't been run already
			for (Iterator iterator = extraPreFunctions.iterator(); iterator
					.hasNext();) {
				FunctionDescriptor function = (FunctionDescriptor) iterator
						.next();
				executeFunction(function, transientVars);
			}
		}

		// go to next step
		// 到下一步去，如果下一步是一个分叉的话，去创建各个步骤！
		// 如果需要会签,那么根据owners的数量创建各个步骤......
		if (theResults[0].getSplit() != 0) {
			log.info("转向用户:" + theResults[0].getOwner());
			// the result is a split request, handle it correctly
			SplitDescriptor splitDesc = wf.getSplit(theResults[0].getSplit());
			boolean team = splitDesc.isTeam();
			Collection results = splitDesc.getResults();
			List splitPreFunctions = new ArrayList();
			List splitPostFunctions = new ArrayList();

			// check all results in the split and verify the input against any
			// validators specified
			// also build up all the pre and post functions that should be
			// called.
			for (Iterator iterator = results.iterator(); iterator.hasNext();) {
				ResultDescriptor resultDescriptor = (ResultDescriptor) iterator
						.next();

				if (resultDescriptor.getValidators().size() > 0) {
					verifyInputs(entry, resultDescriptor.getValidators(),
							Collections.unmodifiableMap(transientVars));
				}

				splitPreFunctions.addAll(resultDescriptor.getPreFunctions());
				splitPostFunctions.addAll(resultDescriptor.getPostFunctions());
			}

			// now execute the pre-functions
			for (Iterator iterator = splitPreFunctions.iterator(); iterator
					.hasNext();) {
				FunctionDescriptor function = (FunctionDescriptor) iterator
						.next();
				executeFunction(function, transientVars);
			}

			if (!action.isFinish()) {
				// now make these steps...
				boolean moveFirst = true;

				theResults = new ResultDescriptor[results.size()];

				results.toArray(theResults);
				if (!team) {
					for (Iterator iterator = results.iterator(); iterator
							.hasNext();) {
						ResultDescriptor resultDescriptor = (ResultDescriptor) iterator
								.next();
						Step moveToHistoryStep = null;

						if (moveFirst) {
							moveToHistoryStep = step;
						}

						long[] previousIds = null;

						if (step != null) {
							previousIds = new long[] { step.getId() };
						}
						orl.setOwner(resultDescriptor, WorkflowResultType.正常分支);
						log.info("设置分支用户" + resultDescriptor.getOwner());
						createNewCurrentStep(resultDescriptor, entry, store,
								action.getId(), moveToHistoryStep, previousIds,
								transientVars);
						moveFirst = false;
					}
				} // end of if (!team)
				else {
					// 需要动态会签的情况
					VariableService vservice = this.configuration
							.getWorkflowVariableService();
					Variable wv = new Variable();
					wv.setEntityId(entry.getId());
					wv.setName("teamstep");

					Iterator iterator = results.iterator();
					ResultDescriptor resultDescriptor = (ResultDescriptor) iterator
							.next();

					// Integer stepId = resultDescriptor.getStep();
					// 动态创建会签步骤,根据传入的用户数目创建
					// 多个分支
					StringBuilder stepIds = new StringBuilder();
					Map<Integer, String> ownerMap = orl.getOwnerMap();
					for (String ows : ownerMap.values()) {
						Step moveToHistoryStep = null;

						if (moveFirst) {
							moveToHistoryStep = step;
						}

						long[] previousIds = null;

						if (step != null) {
							previousIds = new long[] { step.getId() };
						}
						resultDescriptor.setOwner(ows);

						Step sp = createNewCurrentStep(resultDescriptor, entry,
								store, action.getId(), moveToHistoryStep,
								previousIds, transientVars);
						stepIds.append(sp.getId()).append(",");
						moveFirst = false;
					}
					wv.setValue(stepIds.toString());
					vservice.setVariable(wv);

				}
			}// end of if (!action.isFinish())

			// now execute the post-functions
			for (Iterator iterator = splitPostFunctions.iterator(); iterator
					.hasNext();) {
				FunctionDescriptor function = (FunctionDescriptor) iterator
						.next();
				executeFunction(function, transientVars);
			}
		} else if (theResults[0].getJoin() != 0) {
			log.info("转向用户:" + theResults[0].getOwner());
			// this is a join, finish this step...
			JoinDescriptor joinDesc = wf.getJoin(theResults[0].getJoin());
			step = store.markFinished(step, action.getId(), new Date(),
					theResults[0].getOldStatus(), context.getCaller());
			store.moveToHistory(step);
			// ... now check to see if the expression evaluates
			// (get only current steps that have a result to this join)
			Collection joinSteps = new ArrayList();
			joinSteps.add(step);

			// currentSteps = store.findCurrentSteps(id); // shouldn't need to
			// refresh the list
			for (Iterator iterator = currentSteps.iterator(); iterator
					.hasNext();) {
				Step currentStep = (Step) iterator.next();
				if (currentStep.getId() != step.getId()) {
					StepDescriptor stepDesc = wf.getStep(currentStep
							.getStepId());
					if (stepDesc.resultsInJoin(theResults[0].getJoin())) {
						joinSteps.add(currentStep);
					}
				}
			}

			// we also need to check history steps that were finished before
			// this one
			// that might be part of the join
			List historySteps = store.findHistorySteps(entry.getId());

			for (Iterator i = historySteps.iterator(); i.hasNext();) {
				Step historyStep = (Step) i.next();

				if (historyStep.getId() != step.getId()) {
					StepDescriptor stepDesc = wf.getStep(historyStep
							.getStepId());

					if (stepDesc.resultsInJoin(theResults[0].getJoin())) {
						joinSteps.add(historyStep);
					}
				}
			}

			JoinNodes jn = new JoinNodes(joinSteps);
			transientVars.put("jn", jn);

			// todo verify that 0 is the right value for currentstep here
			if (passesConditions(null, joinDesc.getConditions(),
					Collections.unmodifiableMap(transientVars), 0)) {
				// move the rest without creating a new step ...
				ResultDescriptor joinresult = joinDesc.getResult();

				if (joinresult.getValidators().size() > 0) {
					verifyInputs(entry, joinresult.getValidators(),
							Collections.unmodifiableMap(transientVars));
				}

				// now execute the pre-functions
				for (Iterator iterator = joinresult.getPreFunctions()
						.iterator(); iterator.hasNext();) {
					FunctionDescriptor function = (FunctionDescriptor) iterator
							.next();
					executeFunction(function, transientVars);
				}

				long[] previousIds = new long[joinSteps.size()];
				int i = 1;

				for (Iterator iterator = joinSteps.iterator(); iterator
						.hasNext();) {
					Step currentStep = (Step) iterator.next();

					if (currentStep.getId() != step.getId()) {
						// if this is already a history step (eg, for all join
						// steps completed prior to this one),
						// we don't move it, since it's already history.
						if (!historySteps.contains(currentStep)) {
							store.moveToHistory(currentStep);
						}

						previousIds[i] = currentStep.getId();
						i++;
					}
				}

				if (!action.isFinish()) {
					// ... now finish this step normally
					previousIds[0] = step.getId();
					theResults[0] = joinDesc.getResult();
					// we pass in null for the current step since we've already
					// moved it to history above

					orl.setOwner(joinDesc.getResult(), WorkflowResultType.正常汇聚);
					log.info("设置汇聚用户:" + joinDesc.getResult().getOwner());
					createNewCurrentStep(theResults[0], entry, store,
							action.getId(), null, previousIds, transientVars);
				}

				// now execute the post-functions
				for (Iterator iterator = joinresult.getPostFunctions()
						.iterator(); iterator.hasNext();) {
					FunctionDescriptor function = (FunctionDescriptor) iterator
							.next();
					executeFunction(function, transientVars);
				}
			}
		} else {
			// normal finish, no splits or joins
			long[] previousIds = null;

			if (step != null) {
				previousIds = new long[] { step.getId() };
			}
			if (!action.isFinish()) {

				orl.setOwner(theResults[0], WorkflowResultType.普通单步);
				log.info("设置普通单步用户" + theResults[0].getOwner());
				createNewCurrentStep(theResults[0], entry, store,
						action.getId(), step, previousIds, transientVars);
			}
		}

		// postFunctions (BOTH)
		if (extraPostFunctions != null) {
			for (Iterator iterator = extraPostFunctions.iterator(); iterator
					.hasNext();) {
				FunctionDescriptor function = (FunctionDescriptor) iterator
						.next();
				executeFunction(function, transientVars);
			}
		}

		List postFunctions = action.getPostFunctions();

		for (Iterator iterator = postFunctions.iterator(); iterator.hasNext();) {
			FunctionDescriptor function = (FunctionDescriptor) iterator.next();
			executeFunction(function, transientVars);
		}

		// if executed action was an initial action then workflow is activated
		if ((wf.getInitialAction(action.getId()) != null)
				&& (entry.getState() != WorkflowEntry.ACTIVATED)) {
			changeEntryState(entry.getId(), WorkflowEntry.ACTIVATED);
		}

		// if it's a finish action, then we halt
		if (action.isFinish()) {
			completeEntry(action, entry.getId(),
					getCurrentSteps(entry.getId()), WorkflowEntry.COMPLETED);
			return true;
		}
		// get available autoexec actions
		int[] availableAutoActions = getAvailableAutoActions(entry.getId(),
				inputs);
		// we perform the first autoaction that applies, not all of them.
		if (availableAutoActions.length > 0) {
			doAction(entry.getId(), availableAutoActions[0], inputs, owners);
		}

		return false;
	}

	/**
	 * Validates input against a list of ValidatorDescriptor objects.
	 * 
	 * @param entry
	 *            the workflow instance
	 * @param validators
	 *            the list of ValidatorDescriptors
	 * @param transientVars
	 *            the transientVars
	 * @param ps
	 *            the persistence variables
	 * @throws InvalidInputException
	 *             if the input is deemed invalid by any validator
	 */
	protected void verifyInputs(WorkflowEntry entry, List validators,
			Map transientVars) throws WorkflowException {

		for (Iterator iterator = validators.iterator(); iterator.hasNext();) {
			ValidatorDescriptor input = (ValidatorDescriptor) iterator.next();

			if (input != null) {
				String type = input.getType();
				HashMap args = new HashMap(input.getArgs());

				for (Iterator iterator2 = args.entrySet().iterator(); iterator2
						.hasNext();) {
					Map.Entry mapEntry = (Map.Entry) iterator2.next();
					mapEntry.setValue(getConfiguration().getVariableResolver()
							.translateVariables(
									(String) mapEntry.getValue(),
									transientVars,
									this.configuration
											.getWorkflowVariableService(),
									variableSettingService));
				}

				Validator validator = getResolver().getValidator(type, args);

				if (validator == null) {
					context.setRollbackOnly();
					throw new WorkflowException(
							"Could not load validator class");
				}

				try {
					validator.validate(transientVars, args,
							this.configuration.getWorkflowVariableService());
				} catch (InvalidInputException e) {
					throw e;
				} catch (Exception e) {
					context.setRollbackOnly();

					if (e instanceof WorkflowException) {
						throw (WorkflowException) e;
					}

					String message = "An unknown exception occured executing Validator "
							+ validator;
					throw new WorkflowException(message, e);
				}
			}
		}
	}

	/**
	 * check if an action is available or not
	 * 
	 * @param action
	 *            The action descriptor
	 * @return true if the action is available
	 */
	private boolean isActionAvailable(ActionDescriptor action,
			Map transientVars, int stepId) throws WorkflowException {
		if (action == null) {
			return false;
		}
		WorkflowDescriptor wf = getWorkflowDescriptorForAction(action);
		Map cache = (Map) stateCache.get();

		Boolean result = null;

		if (cache != null) {
			result = (Boolean) cache.get(action);
		} else {
			cache = new HashMap();
			stateCache.set(cache);
		}

		if (result == null) {
			RestrictionDescriptor restriction = action.getRestriction();
			ConditionsDescriptor conditions = null;

			if (restriction != null) {
				conditions = restriction.getConditionsDescriptor();
			}

			result = new Boolean(passesConditions(wf.getGlobalConditions(),
					new HashMap(transientVars), stepId)
					&& passesConditions(conditions, new HashMap(transientVars),
							stepId));

			cache.put(action, result);
		}

		return result.booleanValue();
	}

	private Step getCurrentStep(WorkflowDescriptor wfDesc, int actionId,
			List currentSteps, Map transientVars) throws WorkflowException {
		if (currentSteps.size() == 1) {
			return (Step) currentSteps.get(0);
		}

		for (Iterator iterator = currentSteps.iterator(); iterator.hasNext();) {
			Step step = (Step) iterator.next();
			ActionDescriptor action = wfDesc.getStep(step.getStepId())
					.getAction(actionId);

			// $AR init
			if (isActionAvailable(action, transientVars, step.getStepId())) {
				return step;
			}

			// $AR end
		}

		return null;
	}

	private WorkflowDescriptor getWorkflowDescriptorForAction(
			ActionDescriptor action) {
		AbstractDescriptor objWfd = action;

		while (!(objWfd instanceof WorkflowDescriptor)) {
			objWfd = objWfd.getParent();
		}

		WorkflowDescriptor wf = (WorkflowDescriptor) objWfd;

		return wf;
	}

	private boolean canInitializeWorkflow(String workflowName,
			int initialAction, Map transientVars) throws WorkflowException {

		WorkflowService store = getPersistence();
		WorkflowDescriptor wf = store.getWorkflowDescriptor(workflowName);

		ActionDescriptor actionDescriptor = wf.getInitialAction(initialAction);

		if (actionDescriptor == null) {
			throw new InvalidActionException("Invalid Initial Action #"
					+ initialAction);
		}

		RestrictionDescriptor restriction = actionDescriptor.getRestriction();
		ConditionsDescriptor conditions = null;

		if (restriction != null) {
			conditions = restriction.getConditionsDescriptor();
		}

		return passesConditions(conditions, new HashMap(transientVars), 0);
	}

	private Step createNewCurrentStep(ResultDescriptor theResult,
			WorkflowEntry entry, WorkflowService store, int actionId,
			Step currentStep, long[] previousIds, Map transientVars)
			throws WorkflowException {

		try {
			int nextStep = theResult.getStep();

			if (nextStep == -1) {
				if (currentStep != null) {
					nextStep = currentStep.getStepId();
				} else {
					throw new StoreException(
							"Illegal argument: requested new current step same as current step, but current step not specified");
				}
			}

			if (log.isDebugEnabled()) {
				log.debug("Outcome: stepId=" + nextStep + ", status="
						+ theResult.getStatus() + ", owner="
						+ theResult.getOwner() + ", actionId=" + actionId
						+ ", currentStep="
						+ ((currentStep != null) ? currentStep.getStepId() : 0));
			}

			if (previousIds == null) {
				previousIds = new long[0];
			}
			VariableResolver variableResolver = getConfiguration()
					.getVariableResolver();

			String owner = theResult.getOwner();

			// 优先使用描述文件变量当做下步执行者

			String oldStatus = theResult.getOldStatus();
			oldStatus = variableResolver.translateVariables(oldStatus,
					transientVars,
					this.configuration.getWorkflowVariableService(),
					variableSettingService).toString();

			String status = theResult.getStatus();
			status = variableResolver.translateVariables(status, transientVars,
					this.configuration.getWorkflowVariableService(),
					variableSettingService).toString();

			if (currentStep != null) {
				store.markFinished(currentStep, actionId, new Date(),
						oldStatus, context.getCaller());
				store.moveToHistory(currentStep);
			}

			// construct the start date and optional due date
			Date startDate = new Date();
			Date dueDate = null;

			if ((theResult.getDueDate() != null)
					&& (theResult.getDueDate().length() > 0)) {
				Object dueDateObject = variableResolver.translateVariables(
						theResult.getDueDate(), transientVars,
						this.configuration.getWorkflowVariableService(),
						variableSettingService);

				if (dueDateObject instanceof Date) {
					dueDate = (Date) dueDateObject;
				} else if (dueDateObject instanceof String) {
					long offset = 0;

					try {
						offset = Long.parseLong((String) dueDateObject);
					} catch (NumberFormatException e) {
					}

					if (offset > 0) {
						dueDate = new Date(startDate.getTime() + offset);
					}
				} else if (dueDateObject instanceof Number) {
					Number num = (Number) dueDateObject;
					long offset = num.longValue();

					if (offset > 0) {
						dueDate = new Date(startDate.getTime() + offset);
					}
				}
			}

			Step newStep = store.createCurrentStep(entry.getId(), nextStep,
					actionId, owner, startDate, dueDate, status, previousIds);

			transientVars.put("createdStep", newStep);

			if ((previousIds != null) && (previousIds.length == 0)
					&& (currentStep == null)) {
				// At this point, it must be a brand new workflow, so we'll
				// overwrite the empty currentSteps
				// with an array of just this current step
				List currentSteps = new ArrayList();
				currentSteps.add(newStep);
				transientVars.put("currentSteps", new ArrayList(currentSteps));
			}

			WorkflowDescriptor descriptor = (WorkflowDescriptor) transientVars
					.get("descriptor");

			StepDescriptor step = descriptor.getStep(nextStep);

			if (step == null) {
				throw new WorkflowException("[next]step #" + nextStep
						+ " does not exist");
			}

			List preFunctions = step.getPreFunctions();

			for (Iterator iterator = preFunctions.iterator(); iterator
					.hasNext();) {
				FunctionDescriptor function = (FunctionDescriptor) iterator
						.next();
				executeFunction(function, transientVars);
			}

			return newStep;
		} catch (WorkflowException e) {
			context.setRollbackOnly();
			throw e;
		}
	}

	// if (getAvailableActions(id, Collections.emptyMap())
	//
	public int[] getCurrentAvailiableActions(long id, Map inputs) {

		try {
			WorkflowService store = getPersistence();
			WorkflowEntry entry = store.findEntry(id);

			if (entry == null) {
				throw new IllegalArgumentException("No such workflow id " + id);
			}

			if (entry.getState() != WorkflowEntry.ACTIVATED) {
				return new int[0];
			}

			WorkflowDescriptor wf = getConfiguration().getWorkflowService()
					.getWorkflowDescriptor(entry.getWorkflowName());

			if (wf == null) {
				throw new IllegalArgumentException("No such workflow "
						+ entry.getWorkflowName());
			}

			List actionIdList = new ArrayList();
			Map transientVars = (inputs == null) ? new HashMap() : new HashMap(
					inputs);
			Collection currentSteps = store.findCurrentSteps(id);

			populateTransientMap(entry, transientVars, wf.getRegisters(),
					new Integer(0), currentSteps);

			// get global actions
			List globalActions = wf.getGlobalActions();

			for (Iterator iterator = globalActions.iterator(); iterator
					.hasNext();) {
				ActionDescriptor action = (ActionDescriptor) iterator.next();

				RestrictionDescriptor restriction = action.getRestriction();
				ConditionsDescriptor conditions = null;

				transientVars.put("actionId", new Integer(action.getId()));

				if (restriction != null) {
					conditions = restriction.getConditionsDescriptor();
				}

				// todo verify that 0 is the right currentStepId
				// 全局条件和本地条件都通过，则可以视action为可用
				if (passesConditions(wf.getGlobalConditions(), transientVars, 0)
						&& passesConditions(conditions, transientVars, 0)) {
					actionIdList.add(new Integer(action.getId()));
				}
			}

			// TODO 获取当前用户;
			String owner = SpringSecurityUtils.getCurrentUserName();
			// get normal actions
			for (Iterator iterator = currentSteps.iterator(); iterator
					.hasNext();) {
				Step step = (Step) iterator.next();
				if (step.getOwner() != null
						&& step.getOwner().equalsIgnoreCase(owner))
					actionIdList.addAll(getAvailableActionsForStep(wf, step,
							transientVars));
			}

			int[] actions = new int[actionIdList.size()];

			for (int i = 0; i < actions.length; i++) {
				actions[i] = ((Integer) actionIdList.get(i)).intValue();
			}

			return actions;
		} catch (Exception e) {
			log.error("Error checking available actions", e);

			return new int[0];
		}
	}

	/**
	 * @return List&ltActionItem&gt list
	 * @throws WorkflowException 
	 * */
	public List<ActionItem> getActionItem(long id, Map inputs) throws WorkflowException {
		List<ActionItem> actionviews = new ArrayList<ActionItem>();
		String workflowName = getWorkflowName(id);
		WorkflowDescriptor descriptor = getWorkflowDescriptor(workflowName);
		int[] actions = this.getCurrentAvailiableActions(id, inputs);
		// getAvailableActions(workflowId, input);

		for (int action : actions) {
			ActionItem actionview = new ActionItem();
			Step st = getStepIdByActionId(action, id);
			Set<StepDescriptor> steps = getNextSteps(id, action);
			actionview.setNextSteps(steps);
			actionview.setStepId(st.getStepId());
			actionview.setActionName(descriptor.getAction(action).getName());
			actionview.setActionId(action);
			actionview.setWorkflowId(id);
			actionview.setWorkflowName(workflowName);
			actionviews.add(actionview);
		}
		return actionviews;
	}

	@Override
	public ActionItem getActionItemById(int actionId, long id, Map inputs)
			throws InvalidInputException, WorkflowException {
		String workflowName = getWorkflowName(id);
		WorkflowDescriptor descriptor = getWorkflowDescriptor(workflowName);
		int[] actions = this.getCurrentAvailiableActions(id, inputs);
		ActionItem actionview = new ActionItem();
		for (int aid : actions) {
			if (aid != actionId)
				continue;
			Step st = getStepIdByActionId(aid, id);
			actionview.setNextSteps(getNextSteps(id, aid));
			actionview.setStepId(st.getStepId());
			actionview.setActionName(descriptor.getAction(aid).getName());
			actionview.setActionId(aid);
			actionview.setWorkflowId(id);
			actionview.setWorkflowName(workflowName);
			return actionview;
		}
		return null;
	}

	private Step getStepIdByActionId(int actionId, long workflowId) {
		Step tstep = null;
		WorkflowDescriptor descriptor = getWorkflowDescriptor(getWorkflowName(workflowId));
		List csteps = getCurrentSteps(workflowId);
		// 遍历当前步骤 找出与包含活动参数相等的步骤
		outer: for (Object so : csteps) {
			Step step = (HibernateStep) so;
			StepDescriptor sdesc = descriptor.getStep(step.getStepId());
			List actions = sdesc.getActions();
			for (Object adesc : actions) {
				ActionDescriptor asc = (ActionDescriptor) adesc;
				if (asc.getId() == actionId) {
					tstep = step;
					break outer;
				}
			}
		}
		return tstep;
	}

	/**
	 * <dd>后继结果不考虑有条件的 <dd>只考虑无条件结果
	 * 
	 * @return 下一步可能步骤的步骤描述符对象集合
	 * @param workflowId
	 *            工作流编号
	 * @param actionId
	 *            当前活动编号
	 * @throws WorkflowException 
	 ***/
	private Set<StepDescriptor> getNextSteps(long workflowId, int actionId) throws WorkflowException {
		Set<StepDescriptor> nextSteps = Sets.newHashSet();
		WorkflowDescriptor descriptor = getWorkflowDescriptor(getWorkflowName(workflowId));
		HibernateWorkflowEntry entry = (HibernateWorkflowEntry) this.getPersistence().findEntry(workflowId);
		Map<String,Object> transMap = Maps.newHashMap();
		transMap.put("entry", entry);
		ActionDescriptor adesc = descriptor.getAction(actionId);
		ResultDescriptor result = adesc.getUnconditionalResult();
		List results  = adesc.getConditionalResults();
		if(!CollectionUtils.isEmpty(results)){
		   for(Object o: results){
			   ConditionalResultDescriptor cr = (ConditionalResultDescriptor) o;
			   
			   List conds = cr.getConditions();
			   boolean passed = true;
			   for(Object co:conds){
				   ConditionDescriptor cd = (ConditionDescriptor) co;
				   String beanName = cd.getArgs().get("bean.name").toString();
				   //TODO 确定结果条件是否成立
				   Condition sprCond = this.springContext.getBean(beanName, Condition.class);
				   VariableService vservice = this.springContext.getBean(VariableService.class);
				   passed&=sprCond.passesCondition(transMap, cd.getArgs(), vservice);
				  
			   }
			   if(passed){
				   result = cr;
				   break;
			   }
		   }
		}
			
		// List cresults = adesc.getConditionalResults();
		nextSteps.addAll(parseStep(descriptor, result));
		// nextSteps.addAll(parseStep(descriptor, cresults));
		return nextSteps;
	}

	private Set<StepDescriptor> parseStep(WorkflowDescriptor descriptor,
			List<ResultDescriptor> results) {
		Set<StepDescriptor> nextSteps = Sets.newHashSet();
		if (null == results)
			return nextSteps;
		else {
			for (ResultDescriptor result : results)
				nextSteps.addAll(parseStep(descriptor, result));

		}
		return nextSteps;
	}

	private Set<StepDescriptor> parseStep(WorkflowDescriptor descriptor,
			ResultDescriptor results) {
		Set<StepDescriptor> nextSteps = Sets.newHashSet();
		if (results.getStep() != 0) {
			nextSteps.add(descriptor.getStep(results.getStep()));
			return nextSteps;
		} else if (results.getJoin() != 0) {
			JoinDescriptor jdesc = descriptor.getJoin(results.getJoin());
			ResultDescriptor trs = jdesc.getResult();
			nextSteps.add(descriptor.getStep(trs.getStep()));
			return nextSteps;
		} else if (results.getSplit() != 0) {
			SplitDescriptor sdesc = descriptor.getSplit(results.getSplit());
			List trs = sdesc.getResults();
			for (Object o : trs) {
				ResultDescriptor rd = (ResultDescriptor) o;
				nextSteps.add(descriptor.getStep(rd.getStep()));
			}
			return nextSteps;
		}
		return nextSteps;
	}

	@Override
	public Workflow configContext() {
		return this;
	}

	@Resource
	public void setVariableSettingService(
			VariableSettingService processSettingService) {
		this.variableSettingService = processSettingService;
	}

	@Override
	public void setApplicationContext(ApplicationContext springContext)
			throws BeansException {
		this.springContext = springContext;
		
	}

}